﻿using System.Security.Cryptography.X509Certificates;
using Certs.Apis;
using Mapster;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using ProxyServer.Acme;
using ProxyServer.Certs;
using ProxyServer.Endpoints;
using ProxyServer.EntityFrameworkCore;
using ProxyServer.Exceptions;
using Quartz;

namespace ProxyServer.Quartz.Jobs
{
    [DisallowConcurrentExecution, PersistJobDataAfterExecution]
    public class CheckServiceCertificateJob : IJob
    {
        public static JobKey BuildServiceJobKey(Guid serviceId) => new JobKey(nameof(CheckServiceCertificateJob), serviceId.ToString());

        private readonly IServiceScopeFactory _serviceScopeFactory;
        private readonly ILogger _logger;
        private readonly AppDbContext _db;
        private readonly CertsClientProxy _certs;
        private readonly SerivceCertStore _certStore;

        public CheckServiceCertificateJob(
            CertsClientProxy certs,
            SerivceCertStore certStore,
            IServiceScopeFactory serviceScopeFactory, AppDbContext db, ILogger<CheckServiceCertificateJob> logger)
        {
            _serviceScopeFactory = serviceScopeFactory;
            _logger = logger;
            _db = db;
            _certs = certs;
            _certStore = certStore;
        }

        public const string ServiceId = nameof(ServiceId);
        public const string ReCreateOrder = nameof(ReCreateOrder);
        public const string TicketOrderId = nameof(TicketOrderId);
        public const string TicketCreated = nameof(TicketCreated);

        public async Task Execute(IJobExecutionContext context)
        {
            var serviceId = context.MergedJobDataMap.GetGuid(ServiceId);
            var ticketCreated = context.MergedJobDataMap.GetBoolean(TicketCreated);

            var service = await _db.Services.FindAsync([serviceId], context.CancellationToken);

            if (service is null)
            {
                throw new ServiceNotFoundException(serviceId);
            }

            #region  Create new ticket
            if (!ticketCreated)
            {
                var resp = await _certs.Client.Ticket_CreateAsync(new CreateTicketRequest
                {
                    Id = service.AcmeOrderId,
                    Domains = service.Hosts,
                    PfxPassword = string.Empty
                });

                if (resp.StatusCode == 200)
                {
                    ticketCreated = true;
                    context.JobDetail.JobDataMap[TicketCreated] = ticketCreated;
                }
                else
                {
                    ticketCreated = false;
                    context.JobDetail.JobDataMap[TicketCreated] = ticketCreated;
                }
            }

            if (!ticketCreated)
            {
                return;
            }
            #endregion

            #region  Check cert valid or not?
            var cert = await _certStore.GetCertificateAsync(service.AcmeOrderId, context.CancellationToken);
            if (cert is null)
            {
                var certByes = await _certs.DownloadPem(service.AcmeOrderId, context.CancellationToken);
                cert = X509CertificateLoader.LoadCertificate(certByes);
            }

            
            #endregion
        }
    }
}
